package ar.edu.itba.pod.legajo45129.simul.market;

import java.rmi.RemoteException;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.log4j.Logger;

import ar.edu.itba.pod.legajo45129.simul.communication.ConnectionManagerImpl;
import ar.edu.itba.pod.legajo45129.simul.communication.factory.MessageFactory;
import ar.edu.itba.pod.simul.communication.Message;
import ar.edu.itba.pod.simul.local.LocalMarket;
import ar.edu.itba.pod.simul.market.Resource;
import ar.edu.itba.pod.simul.market.ResourceStock;

import com.google.common.base.Preconditions;

public class CopyOfMyMarket extends LocalMarket {
	private static Logger logger = Logger.getLogger(CopyOfMyMarket.class);
	private ConnectionManagerImpl connectionManager;
	
	public CopyOfMyMarket(ConnectionManagerImpl connectionManager) {
		this.connectionManager = connectionManager;
	}

	@Override
	protected void matchBothEnds() {		
		for (ResourceStock buyer : buying) {
			for (ResourceStock seller : selling) {
				if (buyer.resource().equals(seller.resource())) {
					transfer(buyer, seller);
				}
			}
		}
		
		for(ResourceStock buyer : buying.elementSet()){
			int amount = buying.count(buyer);
			if(amount != 0){
				Message message = MessageFactory.ResourceRequestMessage(connectionManager.getNodeId().toString(),
						buyer.resource(), amount);
				logger.debug("market need resources, broadcast " + message);
				try {
					connectionManager.getGroupCommunication().broadcast(message);
				} catch (RemoteException e) {
					logger.error("broadcast message error: " + e.getMessage());
				}
			}
		}
	}

	public void addToSelling(Resource resource, int amount) {
		boolean added = false;
		logger.debug("selling count: " + selling.size());
		for (ResourceStock seller: selling) {
			System.out.println(seller.resource());
			if (seller.resource().equals(resource)) {
				seller.add(amount);
				added = true;
				break;
			}
		}
		
		if (!added) {
			selling.add(new TransferedResourceStock("transfered resource stock", resource), amount);
//			offerMore(new TransferedResourceStock("transfered resource stock", resource), amount);
//			throw new RuntimeException("resource : " + resource.name() +" could not be added to selling");
		}

		
		
		logger.debug("resource: " + resource.name() + " added");
		
	}

	
	public void removeFromSelling(Resource resource, int amount) {
		int count = 0;
		synchronized (selling) {
			for (ResourceStock seller: selling) {
				if (seller.resource().equals(resource)) {
					count += seller.current();
					if (seller.current() >= amount) {
						seller.remove(amount);
						logger.debug("resource: " + resource.name() + " removed");
						return;
					} 
					
//					amount -= seller.current();
//					seller.remove(seller.current());
				}
			}

			logger.debug("selling count of this resource: " + count);
			logger.debug("amount needed to be removed: " + amount);
			throw new RuntimeException("resource: " + resource.name() + " could not be removed from selling");
		}
	}
	
	private class TransferedResourceStock implements ResourceStock{
		AtomicInteger stock = new AtomicInteger(0);
		private String name;
		private Resource resource;

		public TransferedResourceStock(String name, Resource resource) {
			this.resource = resource;
			this.name = name;
		}

		@Override
		public void add(int size) {
			stock.addAndGet(size);
		}

		@Override
		public int current() {
			return stock.get();
		}

		@Override
		public String name() {
			return name;
		}

		@Override
		public void remove(int size) {
			synchronized (stock) {
				Preconditions.checkState(stock.get() >= size);
				stock.addAndGet(-size);
			}
			
		}

		@Override
		public Resource resource() {
			return resource;
		}
		
	}

	public int getStock(Resource resource) {
		int stockMax = 0;
		for (ResourceStock rs: selling.elementSet()) {
			if (rs.resource().equals(resource) && rs.current() > stockMax) {
				stockMax = rs.current();
			}
		}
		
		return stockMax;
	}
	
	
	
	
}
